package jmine.tec.utils.collection;

import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;

/**
 * Mapa de 1 para N. Nao implementa {@link Map} por incoerencias nas APIs
 * 
 * @author takeshi
 * @param <K> o tipo da chave
 * @param <V> o tipo do valor
 */
public interface MultiMap<K, V> {

    /**
     * Devolve a colecao de valores associada a chave passada
     * 
     * @param key chave
     * @return Collection ou null se nao presente
     */
    Collection<? extends V> get(K key);

    /**
     * @return int
     */
    int size();

    /**
     * 
     */
    void clear();

    /**
     * Adiciona um novo valor
     * 
     * @param key a chave
     * @param value o valor
     * @return boolean se true, o valor foi adicionado com exito
     */
    boolean add(K key, V value);

    /**
     * Adiciona varios valores ao mapa
     * 
     * @param map o mapa com os valores a serem adicionados
     */
    void addAll(Map<? extends K, ? extends V> map);

    /**
     * Adiciona varios valores ao mapa
     * 
     * @param map o mapa com os valores a serem adicionados
     */
    void addAll(MultiMap<? extends K, ? extends V> map);

    /**
     * Adiciona varios valores associando a uma chave
     * 
     * @param key a chave
     * @param values a colecao de valores a ser adicionada
     */
    void addAll(K key, Collection<? extends V> values);

    /**
     * Remove um item especifico associado a uma chave. Devolve true se o item foi removido com sucesso
     * 
     * @param key chave
     * @param item item
     * @return boolean
     */
    boolean remove(K key, V item);

    /**
     * Remove todos os itens associados a uma chave. Devolve uma colecao vazia caso nenhum valor esteja associado a chave passada
     * 
     * @param key K
     * @return {@link Collection}
     */
    Collection<? extends V> removeAll(K key);

    /**
     * Conjunto com as chaves previamente associadas
     * 
     * @return {@link Set}
     */
    Set<? extends K> keySet();

    /**
     * Conjunto com todos os valores associados a todas as chaves
     * 
     * @return {@link Collection}
     */
    Collection<? extends V> values();

    /**
     * Verifica se ha algum valor associado a chave passada
     * 
     * @param key chave
     * @return boolean
     */
    boolean containsKey(K key);

    /**
     * Verifica se o valor passado esta associado a alguma chave do mapa (qualquer)
     * 
     * @param value V valor
     * @return boolean
     */
    boolean containsValue(V value);

    /**
     * Verifica se o valor passado esta associado a chave passada
     * 
     * @param key a chave
     * @param value o valor
     * @return boolean
     */
    boolean containsValue(K key, V value);

    /**
     * Transforma este mapa em um {@link Map}. Modificacoes no mapa devolvido nao sao refletidas neste {@link MultiMap}
     * 
     * @return {@link Map}
     */
    Map<K, Collection<V>> toPlainMap();

    /**
     * Devolve uma {@link Collection} com todas as entradas deste mapa. Modificacoes neste mapa nao sao
     * 
     * @return {@link Collection}
     */
    Collection<Entry<K, Collection<V>>> entries();

    /**
     * Devolve um {@link Iterator} com todos os valores associados a todas as chaves
     * 
     * @return {@link Iterator}
     */
    Iterator<Collection<V>> valuesIterator();

    /**
     * Verifica se este mapa esta vazio
     * 
     * @return boolean
     */
    boolean isEmpty();

}
